# -*- coding: utf-8 -*-
# בש״ד
#
# Miraflores Blog for Django - Part of the Cuba Libre Project
# Copyright (C) 2009, Joshua "jag" Ginsberg <jag@flowtheory.net>
# 
# Por mi amor, que inspira a mi cada respiración y que echa de Cuba
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import hashlib
import urllib
import datetime
from django.contrib.syndication.feeds import Feed
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.conf import settings as site_settings
from django.db.models import Count
from django.utils.feedgenerator import Atom1Feed
from miraflores.models import BlogEntry
from miraflores import settings
from tagging.models import TaggedItem
from haystack.query import SearchQuerySet

def hash_username(user_obj):
    return hashlib.sha1('%s:%s' % (user_obj.username, 
                                   site_settings.SECRET_KEY)).hexdigest()

def parse_user_token(token):
    try:
        user_id, hashed_username = token.split(':',1)
    except ValueError:
        return AnonymousUser()
    user_obj = User.objects.get(id=user_id)
    if hashed_username == hash_username(user_obj):
        return user_obj
    else:
        return AnonymousUser()

def generate_user_token(user_obj):
    return '%s:%s' % (user_obj.id, hash_username(user_obj))

class RSSFeed(Feed):
    def get_object(self, bits):
        if len(bits) == 0:
            # normal public subscriber
            self.user_obj = AnonymousUser()
            # return BlogEntry.objects.can_be_seen_by_user(AnonymousUser())
            return 'all', 'all'
        subfeed = bits.pop(0)
        if subfeed == 'tag':
            # We're looking for entries with a certain tag
            tag = bits.pop(0)
            # If there are any bits left, it's a user token
            if bits:
                user_token = bits.pop(0)
                self.user_obj = parse_user_token(user_token)
            else:
                self.user_obj = AnonymousUser()
            # qs = BlogEntry.objects.can_be_seen_by_user(user_obj)
            # return Tag.objects.get_by_model(qs, tag)
            return 'tag', tag
        if subfeed == 'category':
            # We're looking for entries with a certain category
            category_slug = bits.pop(0)
            # If there are any bits left, it's a user token
            if bits:
                user_token = bits.pop(0)
                self.user_obj = parse_user_token(user_token)
            else:
                self.user_obj = AnonymousUser()
            # qs = BlogEntry.objects.can_be_seen_by_user(user_obj)
            # return Tag.objects.get_by_model(qs, tag)
            return 'category', category_slug
        if subfeed == 'search':
            # We're executing a search query
            query = bits.pop(0)
            # If there are any bits left, it's a user token
            if bits:
                user_token = bits.pop(0)
                self.user_obj = parse_user_token(user_token)
            else:
                self.user_obj = AnonymousUser()
            # sqs = SearchQuerySet().models(BlogEntry).filter(content=query)
            # sqs = sqs.order_by('-last_updated')
            # sqs = sqs.load_all()
            # results = map(lambda sr: sr.object.id, sqs)
            # qs = BlogEntry.objects.can_be_seen_by_user(user_obj)
            # return qs.filter(id__in=results)
            return 'search', query
        # in this case, we're expecting subfeed to be a user token
        user_token = subfeed
        self.user_obj = parse_user_token(user_token)
        return 'all', 'all'
        
    def title(self, obj):
        feedtype, arg = obj
        if feedtype == 'all':
            return Site.objects.get_current().name
        elif feedtype == 'tag':
            return u'%s - items tagged %s' % (Site.objects.get_current().name,
                                              arg)
        elif feedtype == 'category':
            return u'%s - items in category %s' % (Site.objects.get_current().name,
                                              arg)
        elif feedtype == 'search':
            return u'%s - search for %s' % (Site.objects.get_current().name,
                                            arg)
    
    def link(self, obj):
        feedtype, arg = obj
        if feedtype == 'all':
            return reverse('miraflores_blog_entry_list')
        elif feedtype == 'tag':
            return reverse('miraflores_tagged_entry_list',
                           args=[arg])
        elif feedtype == 'category':
            return reverse('miraflores_categorized_entry_list',
                           args=[arg])
        elif feedtype == 'search':
            GET_data = urllib.urlencode({'q': arg})
            return reverse('miraflores_search')+'?'+GET_data
    
    description = settings.BLOG_DESCRIPTION or u"None of the news that's fit to print."
    
    def author_name(self):
        authors = User.objects.annotate(entry_count=Count('author__id'))
        authors = authors.filter(entry_count__gt=0)
        return u', '.join(
            map(lambda user: user.first_name+u' '+user.last_name,
                authors))
    
    def author_email(self):
        authors = User.objects.annotate(entry_count=Count('author__id'))
        authors = authors.filter(entry_count__gt=0)
        return u', '.join(map(lambda user: user.email, authors))

    def copyright(self):
        if settings.BLOG_COPYRIGHT:
            return settings.BLOG.COPYRIGHT
        else:
            return u'All content copyright (C) %s %s' % (
                datetime.date.today().year,
                self.author_name())
    
    ttl = str(settings.BLOG_FEED_TTL) or '3600'
    
    def items(self, obj):
        feedtype, arg = obj
        if feedtype == 'all':
            return BlogEntry.objects.can_be_seen_by_user(self.user_obj)
        elif feedtype == 'tag':
            qs = BlogEntry.objects.can_be_seen_by_user(self.user_obj)
            return TaggedItem.objects.get_by_model(qs, arg)
        elif feedtype == 'category':
            qs = BlogEntry.objects.can_be_seen_by_user(self.user_obj)
            return qs.filter(categories__slug=arg)
        elif feedtype == 'search':
            sqs = SearchQuerySet().models(BlogEntry).filter(content=arg)
            sqs = sqs.order_by('-last_updated')
            sqs = sqs.load_all()
            results = map(lambda sr: sr.object.id, sqs)
            qs = BlogEntry.objects.can_be_seen_by_user(self.user_obj)
            return qs.filter(id__in=results)
    
    def item_link(self, item):
        return item.get_absolute_url()
    
    def item_author_name(self, item):
        return item.author.first_name + u' ' + item.author.last_name
    
    def item_author_email(self, item):
        return item.author.email
    
    def item_pubdate(self, item):
        return item.last_updated
    
    def item_categories(self, item):
        return item.categories.all()

class AtomFeed(RSSFeed):
    feed_type = Atom1Feed
    subtitle = RSSFeed.description

